<template>
  <div>
    <div :id="'container' + id" class="point-cloud-container" :style="'height: ' + height + 'vh;'" v-loading="loading">
      <canvas :id="'canvas3d' + id" />
    </div>
    <div class="right-panel-tools" style="position: absolute; right: 0; top: 0; z-index: 2000">
      <el-tooltip effect="light" content="查看" placement="right-end">
        <el-button circle size="mini" icon="el-icon-search" @click="changeLabelTool('view')" style="margin-left: 0" />
      </el-tooltip>
      <el-tooltip effect="light" content="保存" placement="right-end">
        <el-button
          circle
          size="mini"
          icon="fa fa-floppy-o"
          :disabled="tmpSplitPoints.length == 0 && tmpMinusSplitPoints.length == 0"
          @click="addSplitMarkAnnotation(tmpSplitPoints, tmpMinusSplitPoints, addSplitCallback)"
          style="margin-left: 0"
        />
      </el-tooltip>
      <el-tooltip v-if="checkrole(['admin', 'checker', 'marker'])" effect="light" content="画框" placement="right-end">
        <el-button circle size="mini" icon="fa fa-cube" @click="schangeLabelTool('cube')" style="margin-left: 0" />
      </el-tooltip>
      <el-tooltip effect="light" content="选点" placement="right-end">
        <el-button
          circle
          size="mini"
          icon="fa fa-plus-square-o"
          @click="changeLabelTool('point')"
          style="margin-left: 0"
        />
      </el-tooltip>
      <el-tooltip effect="light" content="删点" placement="right-end">
        <el-button
          circle
          size="mini"
          icon="el-icon-remove-outline"
          @click="changeLabelTool('minus')"
          style="margin-left: 0"
        />
      </el-tooltip>
      <el-tooltip effect="light" content="查看" placement="right-end">
        <el-button
          circle
          size="mini"
          icon="el-icon-view"
          @click="planeViewDrawer = !planeViewDrawer"
          style="margin-left: 0"
        />
      </el-tooltip>
    </div>
    <el-collapse-transition>
      <div v-show="planeViewDrawer" class="plan-view-drawer transition-box">
        <el-card shadow="never" class="plane-view-card" :body-style="{ height: 'calc(83vh - 28px)', padding: 0 }">
          <div slot="header" class="clearfix">
            <span>三维平面视图</span>
          </div>
          <PlaneView
            id="001"
            :type="0"
            ref="planeView001"
            height="calc((83vh - 28px)/3)"
            v-bind:visable="planeViewDrawer"
            v-bind:render-type="renderType"
            v-bind:attribute-names="attributeNames"
            v-bind:color-names="colorNames"
            v-bind:points-cloud-data="pointsCloudData"
            v-bind:selected-object="selectedObject"
          >
          </PlaneView>
          <PlaneView
            id="002"
            :type="1"
            ref="planeView002"
            height="calc((83vh - 28px)/3)"
            v-bind:visable="planeViewDrawer"
            v-bind:render-type="renderType"
            v-bind:attribute-names="attributeNames"
            v-bind:color-names="colorNames"
            v-bind:points-cloud-data="pointsCloudData"
            v-bind:selected-object="selectedObject"
          >
          </PlaneView>
          <PlaneView
            id="003"
            :type="2"
            ref="planeView003"
            height="calc((83vh - 28px)/3)"
            v-bind:visable="planeViewDrawer"
            v-bind:render-type="renderType"
            v-bind:attribute-names="attributeNames"
            v-bind:color-names="colorNames"
            v-bind:points-cloud-data="pointsCloudData"
            v-bind:selected-object="selectedObject"
          >
          </PlaneView>
        </el-card>
      </div>
    </el-collapse-transition>
  </div>
</template>
<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { PCDLoader } from './PCDLoader.js'
import { ResourceTracker } from './ResourceTracker.js'
import { pointsCloudDetails, pcdBlob, pcdBlobWithFlag } from '@/api/mark/onlineCheck'
import { checkRole } from '@/utils/permission'
import { colorRender } from './PCDColorRender.js'
import PlaneView from '../PlaneView'
import { listRemarkBall } from '@/api/mark/remarkBall'
import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js'
import { SelectionBox } from './SelectionBox.js'
import { SelectionHelper } from './SelectionHelper.js'
import { ConvexGeometry } from 'three/examples/jsm/geometries/ConvexGeometry.js'
import { TransformControls } from './TransformControls.js'
import Cookies from 'js-cookie'
export default {
  name: 'PointCloud',
  props: {
    height: Number,
    id: String,
    taskId: [String, Number],
    HideTip: Function,
    ShowTip: Function,
    renderType: String,
    cameraPosition: {},
    highLightCubePoints: [String, Boolean],
    attributeNames: {},
    colorNames: {},
    loading: Boolean,
    sync_highlight_objects: Function,
    sync_clear_highlight_objects: Function,
    changePage: Function,
    setPosition: Function,
    elementsRemark: {},
    handleElementComments: Function,
    changeCubeInfo: Function,
    // markAnnotationList: Array
    addSplitMarkAnnotation: Function,
  },
  components: {
    PlaneView,
  },
  computed: {
    markAnnotations() {
      return this.$store.state.markData.markAnnotations
    },
    remarkList() {
      return this.$store.state.markData.remarkList
    },
  },
  data() {
    return {
      mQaResultId: [String, Number],
      planeViewDrawer: false,
      animationFrameId: undefined,
      mouseDown: false,
      renderEnabled: false,
      pointTextFontSize: 48,
      isFullscreen: false,
      selectedObject: {
        mMarkAnnotationId: null,
        name: '',
        a1: '',
        a2: '',
        a3: '',
        a4: '',
        a5: '',
        a6: '',
        a7: '',
        a8: '',
        remark: '',
        attributes: [],
        type: '',
        imageIndex: '',
        errorType: '',
        mPoint: {
          x: -1,
          y: -1,
          z: -1,
        },
        elementInstance: null,
        position: null,
      },
      toolTopbody: '',
      ctx: null,
      container: null,
      camera: null,
      scene: null,
      highlight_points: null,
      controls: null,
      transformControls: null,
      renderer: null,
      points: null,
      dopplerLines: null,
      keyPoints: [],
      cubeList: new Array(),
      splitPoints: new Array(),
      cubeInstances: new Array(),
      cubeMap: new Map(),
      remarkLabelList: new Array(),
      lineList: new Array(),
      raycaster: null,
      mouse: null,
      pointsCloudData: null,
      annotation: null,
      annotationMap: new Map(),
      currentIndex: -1,
      fileList: {},
      remark: null,
      elements_3D: [],
      INTERSECTED: null,
      selectPointObject: null,
      labelRenderer: null,
      showLabel: true,
      resTracker: null,
      track: null,
      loader: new PCDLoader(),
      pointsFocus: null,
      // 毫米波雷达界面显示激光雷达
      pointsLidar: null,
      selectionBox: null,
      helper: null,
      splitObjects: new Map(),
      tmpSplitPoints: [],
      tmpMinusSplitPoints: [],
      splitRange: null,
    }
  },
  methods: {
    // 初始化3D视窗相关对象
    init() {
      this.resTracker = new ResourceTracker()
      this.track = this.resTracker.track.bind(this.resTracker)
      this.container = document.getElementById('container' + this.id)
      let canvas3d = document.getElementById('canvas3d' + this.id)

      this.raycaster = new THREE.Raycaster()
      this.mouse = new THREE.Vector2()
      this.scene = new THREE.Scene()
      this.camera = new THREE.PerspectiveCamera(
        10,
        this.container.offsetWidth / this.container.offsetHeight,
        0.1,
        10000
      )
      try {
        let tmpPosition = JSON.parse(this.cameraPosition)
        this.camera.position.x = tmpPosition.x
        this.camera.position.y = tmpPosition.y
        this.camera.position.z = tmpPosition.z
      } catch {
        this.camera.position.x = 0
        this.camera.position.y = 400
        this.camera.position.z = 300
      }
      this.camera.up.set(0, 0, 1)
      this.camera.lookAt(new THREE.Vector3(0, 0, 0))
      this.scene.add(this.camera)

      let ambientLight = new THREE.AmbientLight(0xffffff)
      this.scene.add(ambientLight)

      this.scene = new THREE.Scene()
      this.scene.background = new THREE.Color(0x111111)

      let showGridHelper = this.selectDictLabel(this.attributeNames, 'gridHelper')
      if (showGridHelper) {
        try {
          let gridHelper = new THREE.GridHelper(parseFloat(showGridHelper), parseFloat(showGridHelper))
          gridHelper.rotation.x = Math.PI / 2
          this.scene.add(gridHelper)
        } catch {}
      }

      // 添加坐标轴
      let axesHelper = new THREE.AxesHelper(5)
      this.scene.add(axesHelper)

      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        canvas: canvas3d,
        powerPreference: 'high-performance',
        preserveDrawingBuffer: true,
      })
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.setSize(this.container.offsetWidth, this.container.offsetHeight)
      this.container.appendChild(this.renderer.domElement)

      this.labelRenderer = new CSS2DRenderer()
      this.labelRenderer.setSize(this.container.offsetWidth, this.container.offsetHeight)
      this.labelRenderer.domElement.style.position = 'absolute'
      this.labelRenderer.domElement.style.top = '0px'
      this.labelRenderer.domElement.style.pointerEvents = 'none'
      this.container.appendChild(this.labelRenderer.domElement)

      this.controls = new OrbitControls(this.camera, this.renderer.domElement)
      this.controls.zoomSpeed = 3
      this.controls.panSpeed = 2
      this.controls.rotateSpeed = 1
      this.controls.maxPolarAngle = Math.PI * 0.5
      this.controls.enableKeys = false
      // this.controls.enableDamping = true;
      this.controls.addEventListener('change', this.requestRenderIfNotRequested)

      this.transformControls = new TransformControls(this.camera, this.renderer.domElement)
      this.transformControls.addEventListener('dragging-changed', (event) => {
        this.controls.enabled = !event.value
        console.log(event)
      })

      this.scene.add(this.transformControls)

      this.renderer.domElement.addEventListener('mousemove', this.onMouseMove, false)
      this.renderer.domElement.addEventListener('mousedown', this.onMouseDown, false)
      this.renderer.domElement.addEventListener('mouseup', this.onMouseUp, false)
      this.renderer.domElement.addEventListener('wheel', this.onMouseWheel, false)

      this.selectionBox = new SelectionBox(this.camera, this.scene)
      this.selectionBox.labelTool = 'view'
      this.helper = new SelectionHelper(this.selectionBox, this.renderer, 'selectBox')

      document.addEventListener('pointerdown', (event) => {
        if (!this.renderer) return

        if (event.shiftKey && this.selectionBox.labelTool !== 'view') {
          this.controls.enabled = false
        } else {
          return
        }

        const rect = this.renderer.domElement.getBoundingClientRect()

        this.selectionBox.startPoint.set(
          ((event.clientX - rect.left) / rect.width) * 2 - 1,
          -((event.clientY - rect.top) / rect.height) * 2 + 1,
          0.5
        )
      })

      document.addEventListener('pointerup', (event) => {
        if (!this.renderer) return

        if (event.shiftKey && this.selectionBox.labelTool !== 'view') {
          this.controls.enabled = true
        } else {
          return
        }

        const rect = this.renderer.domElement.getBoundingClientRect()

        this.selectionBox.endPoint.set(
          ((event.clientX - rect.left) / rect.width) * 2 - 1,
          -((event.clientY - rect.top) / rect.height) * 2 + 1,
          0.5
        )

        const selected = this.selectionBox.select()

        this.tmpSplitPoints.push(...selected.pointsIndex)
        this.tmpMinusSplitPoints.push(...selected.minusPointsIndex)
        let tmpPoints = []
        this.tmpSplitPoints.forEach((index) => {
          if (this.tmpMinusSplitPoints.indexOf(index) == -1 && tmpPoints.indexOf(index) == -1) {
            tmpPoints.push(index)
          }
        })
        this.tmpSplitPoints = tmpPoints
        tmpPoints = []
        this.tmpMinusSplitPoints.forEach((index) => {
          if (this.tmpSplitPoints.indexOf(index) == -1 && tmpPoints.indexOf(index) == -1) {
            tmpPoints.push(index)
          }
        })
        this.tmpMinusSplitPoints = tmpPoints

        this.pointsCloudData.needsUpdate = true

        this.requestRenderIfNotRequested()
      })

      window.addEventListener('keypress', (event) => {
        switch (event.key || String.fromCharCode(event.keyCode || event.charCode)) {
          case '+':
            if (this.points && this.points.material.size < 8) {
              this.points.material.size *= 1.1
              this.splitPoints.forEach((pointsMesh) => {
                pointsMesh.material.size *= 1.1
                pointsMesh.material.needsUpdate = true
              })
              this.points.material.needsUpdate = true
            }
            break

          case '_':
            if (this.points && this.points.material.size > 1) {
              this.points.material.size /= 1.1
              this.splitPoints.forEach((pointsMesh) => {
                pointsMesh.material.size /= 1.1
                pointsMesh.material.needsUpdate = true
              })
              this.points.material.needsUpdate = true
            }
            break
        }

        Cookies.remove('pointSize')
        Cookies.set('pointSize', this.points.material.size, { expires: 30 })
        this.renderer.render(this.scene, this.camera)
      })
    },
    // 获取点云数据
    async getPointsCloud(
      fileList,
      currentIndex,
      mQaResultId,
      playModel = false,
      showAttributesText2D = true,
      pcdFlag = null
    ) {
      this.$emit('update.loading', !playModel)
      this.showLabel = showAttributesText2D
      this.fileList = fileList
      this.currentIndex = currentIndex
      // this.renderEnabled = true;
      this.mQaResultId = mQaResultId
      this.selectedObject = {
        a1: '',
        remark: '',
        attributes: [],
        type: '',
        imageIndex: '',
      }

      for (let key in this.elementsRemark) {
        delete this.elementsRemark[key]
      }
      if (!playModel) {
        const storeKey = 'TaskId:' + this.taskId + ';mQaResultId:' + mQaResultId
        const readValue = this.remarkList.get(storeKey)
        if (readValue) {
          readValue.forEach((ball) => {
            if (ball.trackId) {
              let key = ball.trackId
              if (!key.startsWith('lou-')) {
                key += '-' + ball.mType
              }
              this.elementsRemark[key] = ball.remark
              this.elementsRemark['ball-' + key] = ball
            }
          })
        } else {
          await listRemarkBall({ taskId: this.taskId, mQaResultId: mQaResultId }).then((response) => {
            let remarkBallList = response.rows
            if (remarkBallList) {
              remarkBallList.forEach((ball) => {
                if (ball.trackId) {
                  let key = ball.trackId
                  if (!key.startsWith('lou-')) {
                    key += '-' + ball.mType
                  }
                  this.elementsRemark[key] = ball.remark
                  this.elementsRemark['ball-' + key] = ball
                }
              })
            }
          })
        }
      }

      if (pcdFlag) {
        this.$get(
          pcdFlag + mQaResultId,
          (blobFromIndexedDB) => {
            let blobUrl = URL.createObjectURL(blobFromIndexedDB.blob)
            this.loader.track = this.track
            this.loader.renderType = this.renderType
            this.loader.load(blobUrl, (points) => {
              blobUrl = URL.revokeObjectURL(blobUrl)
              this.pointsCloudData = points
              this.annotation = null
              this.threejsRender(playModel)
            })
            blobFromIndexedDB = null
          },
          () => {
            pcdBlobWithFlag(mQaResultId, pcdFlag).then((response) => {
              let blob = new Blob([response.data], { type: 'application/octet-stream' })
              let blobUrl = URL.createObjectURL(blob)
              this.loader.track = this.track
              this.loader.renderType = this.renderType
              this.loader.load(blobUrl, (points) => {
                blobUrl = URL.revokeObjectURL(blobUrl)
                this.pointsCloudData = points
                this.annotation = null
                this.threejsRender(playModel)
                let _data = {
                  blob: blob,
                  file_name: pcdFlag + mQaResultId,
                }
                this.$save(_data)
                _data = null
                blob = null
              })
            })
          }
        )
      } else {
        const readValue = this.markAnnotations.get('MA:' + mQaResultId + '')
        if (readValue) {
          this.$get(
            mQaResultId,
            (blobFromIndexedDB) => {
              let blobUrl = URL.createObjectURL(blobFromIndexedDB.blob)
              this.loader.track = this.track
              this.loader.renderType = this.renderType
              this.loader.load(blobUrl, (points) => {
                blobUrl = URL.revokeObjectURL(blobUrl)
                this.pointsCloudData = points
                this.annotation = readValue
                this.threejsRender(playModel)
              })
              blobFromIndexedDB = null
            },
            () => {
              pcdBlob(mQaResultId).then((response) => {
                let blob = new Blob([response.data], { type: 'application/octet-stream' })
                let blobUrl = URL.createObjectURL(blob)
                this.loader.track = this.track
                this.loader.renderType = this.renderType
                this.loader.load(blobUrl, (points) => {
                  blobUrl = URL.revokeObjectURL(blobUrl)
                  this.pointsCloudData = points
                  this.annotation = readValue
                  this.threejsRender(playModel)
                  let _data = {
                    blob: blob,
                    file_name: mQaResultId,
                  }
                  this.$save(_data)
                  _data = null
                  blob = null
                })
              })
            }
          )
        } else {
          console.debug('cache not found:', mQaResultId)
          pointsCloudDetails(mQaResultId).then((res) => {
            if (res.fileType === 'pcd') {
              this.markAnnotations.set('MA:' + mQaResultId + '', res.annotation)
              this.$get(
                mQaResultId,
                (blobFromIndexedDB) => {
                  let blobUrl = URL.createObjectURL(blobFromIndexedDB.blob)
                  this.loader.track = this.track
                  this.loader.renderType = this.renderType
                  this.loader.load(blobUrl, (points) => {
                    blobUrl = URL.revokeObjectURL(blobUrl)
                    this.pointsCloudData = points
                    this.annotation = res.annotation
                    this.threejsRender(playModel)
                  })
                },
                () => {
                  pcdBlob(mQaResultId).then((response) => {
                    let blob = new Blob([response.data], { type: 'application/octet-stream' })
                    let blobUrl = URL.createObjectURL(blob)
                    this.loader = new PCDLoader()
                    this.loader.track = this.track
                    this.loader.renderType = this.renderType
                    this.loader.load(blobUrl, (points) => {
                      blobUrl = URL.revokeObjectURL(blobUrl)
                      this.pointsCloudData = points
                      this.annotation = res.annotation
                      this.threejsRender(playModel)
                      let _data = {
                        blob: blob,
                        file_name: mQaResultId,
                      }
                      this.$save(_data)
                      _data = null
                      blob = null
                    })
                  })
                }
              )
            } else if (res.fileType === 'jbin') {
              this.pointsCloudData = this.loadJsonPCD(res.pointsCloud)
              this.annotation = res.annotation
              this.threejsRender(playModel)
            }
          })
        }

        let radarView = this.selectDictLabel(this.attributeNames, 'radarView')
        if (radarView == 'true') {
          pcdBlobWithFlag(mQaResultId, 'Bumper').then((response) => {
            const blob = new Blob([response.data], { type: 'application/octet-stream' })
            let blobUrl = URL.createObjectURL(blob)
            this.loader.track = this.track
            this.loader.renderType = 'benzLabel'
            this.loader.load(blobUrl, (points) => {
              blobUrl = URL.revokeObjectURL(blobUrl)
              if (this.pointsLidar) {
                this.scene.remove(this.pointsLidar)
                this.pointsLidar.geometry.dispose()
                this.pointsLidar.material.dispose()
              }
              this.pointsLidar = points.children[points.children.length - 1]
              this.pointsLidar.isBackground = true
              this.pointsLidar.material.size = 1
              this.scene.add(this.pointsLidar)
              this.renderer.render(this.scene, this.camera)
              this.labelRenderer.render(this.scene, this.camera)
            })
          })
        }
      }
    },
    threejsRender(playModel) {
      this.addPoints()
      this.$emit('update.loading', false)
      this.render()
      this.asyncAddCube(playModel).then(
        (message) => {
          this.renderer && this.renderer.render(this.scene, this.camera)
          this.labelRenderer.render(this.scene, this.camera)
          this.$store.state.markData.playStatus.pcd = true
        },
        (message) => {
          console.log(message)
        }
      )
      this.setPosition(this.selectedObjectA1, null, '', null, null, null, null, null)
    },
    // 异步渲染矩形图形
    asyncAddCube(playModel) {
      let promise1 = new Promise((resolve, reject) => {
        this.addCube(playModel)
        resolve('cube loaded.')
      })
      return promise1
    },
    // 获取a1对象的属性值
    getSelectedObjectAttributes(a1) {
      for (let i = 0; i < this.cubeList.length; i++) {
        if (this.cubeList[i].tag) {
          const _array = this.cubeList[i].tag.split(';')
          if (a1 == _array[1]) {
            const attributes = []
            for (let i = 1; i <= 9; i++) {
              if (_array[i] && _array[i] != null && _array[i] != '' && _array[i] != 'null') {
                try {
                  let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'a' + i + '_3d'))
                  let _values = jsonObject.values[_array[i]]
                  if (_values == null || _values == undefined || _values == '') _values = _array[i]
                  let key = jsonObject.typeDesc
                  let value = _values
                  let _data = {
                    key,
                    value,
                  }
                  attributes.push(_data)
                } catch {}
              }
            }
            return attributes
          }
        }
      }
      return []
    },
    clear_highlight_objects() {
      if (this.highlight_points) {
        this.scene.remove(this.highlight_points)
      }
    },
    // 定位缩放视图到选中矩形，并高亮矩形
    highlight_objects(eventSource, selectedObject, isZoom = true, hideOther = false) {
      this.selectedObject = selectedObject
      // 高亮3D对象
      let eight_points = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
      let colors = [1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0]
      let found = false
      for (let i = 0; i < this.elements_3D.length; i++) {
        if (this.selectedObject.a1 == this.elements_3D[i].trackId) {
          eight_points = this.elements_3D[i].eight_points
          found = true
          break
        }
      }
      let tmpCube = null

      for (let i = 0; i < this.cubeList.length; i++) {
        if (this.cubeList[i].tag) {
          if (this.selectedObject.a1 == this.cubeList[i].tag.split(';')[1]) {
            tmpCube = this.cubeList[i]
            tmpCube.visible = true
            // break;
          } else {
            this.cubeList[i].visible = !hideOther
            this.cubeList[i].arrow.visible = !hideOther
            this.cubeList[i].directLine.visible = !hideOther
            this.cubeList[i].line.visible = !hideOther
            this.cubeList[i].label.visible = !hideOther
          }
        }
      }

      if (hideOther) {
        this.splitObjects.forEach((element) => {
          this.hideSplitInstance(element, false)
          // if(element.label)
          //   element.label.visible = false;
        })
        this.splitPoints.forEach((pointsMesh) => {
          pointsMesh.visible = false
        })
      } else {
        this.splitObjects.forEach((element) => {
          this.addSplitInstance(element, false)
          // if(element.label)
          //   element.label.visible = true;
        })
        this.splitPoints.forEach((pointsMesh) => {
          pointsMesh.visible = true
        })
      }
      let geometry_highlight = this.track(new THREE.BufferGeometry())
      let canvas_temp0 = document.createElement('canvas')
      canvas_temp0.width = 100
      canvas_temp0.height = 100
      let context0 = canvas_temp0.getContext('2d')
      context0.fillStyle = '#ffffff'
      context0.arc(50, 50, 45, 0, 2 * Math.PI)
      context0.fill()
      let texture0 = this.track(new THREE.Texture(canvas_temp0))
      texture0.needsUpdate = true
      let material_hightlight = this.track(
        new THREE.PointsMaterial({ size: 8, vertexColors: THREE.VertexColors, depthTest: false, map: texture0 })
      )
      material_hightlight.sizeAttenuation = false
      geometry_highlight.setAttribute('position', new THREE.Float32BufferAttribute(eight_points, 3))
      geometry_highlight.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3))

      if (this.highlight_points) {
        this.scene.remove(this.highlight_points)
      }
      if (found == true) {
        if (tmpCube && this.selectedObject.type == '3d') {
          // 更新验收标识
          if (this.elementsRemark[this.selectedObject.a1 + '-3d']) {
            this.scene.add(tmpCube.remarkLabel)
            this.remarkLabelList.push(tmpCube.remarkLabel)
          } else {
            this.scene.remove(tmpCube.remarkLabel)
            for (let i = 0; i < this.remarkLabelList.length; i++) {
              if (this.remarkLabelList[i].tag && this.remarkLabelList[i].tag == tmpCube.remarkLabel.tag) {
                this.remarkLabelList.splice(i, 1)
                break
              }
            }
          }
        }

        this.highlight_points = this.track(new THREE.Points(geometry_highlight, material_hightlight))
        this.scene.add(this.highlight_points)

        if (isZoom) {
          // 点击3d矩形高亮并缩放三维视角旋转问题，之所以会旋转是因为在缩放摄像机时，从摄像机当前坐标
          // 调整了lookAt到新坐标再拉近距离，在三维透视里就会有角度变化。处理办法就是不改变新lookAt对应的摄像机的角度，然后再拉近
          let cubeCenterPoint = this.calcCubeCenterPoint(eight_points)
          // 查找矩形的中心位置，计算长宽高的中点，用长宽高的一半加上x,y,z轴最小值
          let x = cubeCenterPoint.x
          let y = cubeCenterPoint.y
          let z = cubeCenterPoint.z
          if (
            this.selectedObject.mPoint.x != -1 &&
            this.selectedObject.mPoint.y != -1 &&
            this.selectedObject.mPoint.z != -1
          ) {
            x = this.selectedObject.mPoint.x
            y = this.selectedObject.mPoint.y
            z = this.selectedObject.mPoint.z
          }
          //distance为距离系数，值越小距离越近，下面是计算矩形中心点到摄像机的三维空间内直线长度距离，设为1时摄像机的x,y与矩形第一个点的x,y接近，z相差摄像机的俯视高度差，
          const distance = 10 * Math.max(cubeCenterPoint.maxL, cubeCenterPoint.maxW, cubeCenterPoint.maxH)
          let selectCenterPoint = this.calcCameraOffsetPosition(cubeCenterPoint, distance)
          this.controls.target.copy({ x, y, z })
          this.camera.position.set(selectCenterPoint.x1, selectCenterPoint.y1, selectCenterPoint.z1)
          this.camera.lookAt(x, y, z)
          this.camera.updateMatrix()
          this.controls.update()
        }

        let cubeObj = this.cubeMap.get(this.selectedObject.a1)
        this.$refs.planeView001.rectPoints(cubeObj)
        this.$refs.planeView002.rectPoints(cubeObj)
        this.$refs.planeView003.rectPoints(cubeObj)
      }

      this.renderer.render(this.scene, this.camera)
      this.labelRenderer.render(this.scene, this.camera)
    },
    showMarkAnnotations(mMarkAnnotationIds) {
      for (let i = 0; i < this.cubeList.length; i++) {
        if (this.cubeList[i].mMarkAnnotationId) {
          const markAnnotation = this.cubeList[i]
          if (mMarkAnnotationIds.indexOf(markAnnotation.mMarkAnnotationId) != -1) {
            markAnnotation.show()
          } else {
            markAnnotation.hide()
          }
        }
      }

      this.splitObjects.forEach((element, key) => {
        if (mMarkAnnotationIds.indexOf(key) != -1) this.addSplitInstance(element, false)
        else this.hideSplitInstance(element, false)
      })

      this.splitPoints.forEach((pointsMesh) => {
        if (mMarkAnnotationIds.indexOf(pointsMesh.mMarkAnnotationId) != -1) pointsMesh.visible = true
        else pointsMesh.visible = false
      })

      this.renderer.render(this.scene, this.camera)
      this.labelRenderer.render(this.scene, this.camera)
    },
    // 矩形定位缩放时，计算摄像机移动后的坐标
    calcCameraOffsetPosition(selectCubeCenterPoint, distance) {
      // x0,y0,z0为摄像机重新定位前的位置
      let x0 = this.camera.position.x
      let y0 = this.camera.position.y
      let z0 = this.camera.position.z
      // 根据新旧目标位移差计算摄像机新坐标
      x0 = selectCubeCenterPoint.x - this.controls.target.x + x0
      y0 = selectCubeCenterPoint.y - this.controls.target.y + y0
      z0 = selectCubeCenterPoint.z - this.controls.target.z + z0
      let x = selectCubeCenterPoint.x
      let y = selectCubeCenterPoint.y
      let z = selectCubeCenterPoint.z
      // 计算拉近摄像机后摄像机坐标
      let x1 = (distance * (x0 - x)) / Math.sqrt((x0 - x) * (x0 - x) + (y0 - y) * (y0 - y) + (z0 - z) * (z0 - z)) + x
      let y1 = (distance * (y0 - y)) / Math.sqrt((x0 - x) * (x0 - x) + (y0 - y) * (y0 - y) + (z0 - z) * (z0 - z)) + y
      let z1 = (distance * (z0 - z)) / Math.sqrt((x0 - x) * (x0 - x) + (y0 - y) * (y0 - y) + (z0 - z) * (z0 - z)) + z
      return { x1: x1, y1: y1, z1: z1 }
    },
    // 计算矩形的中心点坐标
    calcCubeCenterPoint(eight_points) {
      // 找出矩形最长边长度值，乘以distance系数，让矩形最大边可以完整显示在摄像机内
      let maxL = 0,
        maxW = 0,
        maxH = 0
      for (let i = 3; i < 24; i += 3) {
        maxL = Math.max(Math.abs(eight_points[i] - eight_points[i - 3]), maxL)
        maxW = Math.max(Math.abs(eight_points[i + 1] - eight_points[i + 1 - 3]), maxW)
        maxH = Math.max(Math.abs(eight_points[i + 2] - eight_points[i + 2 - 3]), maxH)
      }
      // 查找矩形的中心位置，计算长宽高的中点，用长宽高的一半加上x,y,z轴最小值
      let x = Math.min(eight_points[0], eight_points[6]) + maxL / 2
      let y = Math.min(eight_points[1], eight_points[7]) + maxW / 2
      let z = Math.min(eight_points[2], eight_points[23]) + maxH / 2
      return {
        x: x,
        y: y,
        z: z,
        maxL: maxL,
        maxW: maxW,
        maxH: maxH,
      }
    },
    // 添加点云数据到3D视窗
    addPoints() {
      if (this.splitRange) {
        if (this.splitRange.pointsMesh) this.scene.remove(this.splitRange.pointsMesh)
        this.scene.remove(this.splitRange)
      }
      this.splitPoints.forEach((pointsMesh) => {
        this.scene.remove(pointsMesh)
      })
      for (let i = 0; i < this.cubeList.length; i++) {
        this.scene.remove(this.cubeList[i])
      }
      for (let i = 0; i < this.lineList.length; i++) {
        this.scene.remove(this.lineList[i])
      }
      for (let i = 0; i < this.remarkLabelList.length; i++) {
        this.scene.remove(this.remarkLabelList[i])
      }
      if (this.points) {
        try {
          this.scene.remove(this.points)
          // this.points.geometry.dispose();
          // this.points.material.dispose();
        } catch (e) {
          console.log(e)
        }
      }
      if (this.pointsFocus) {
        this.scene.remove(this.pointsFocus)
        this.pointsFocus.geometry.dispose()
        this.pointsFocus.material.dispose()
      }
      if (this.keyPoints.length > 0) {
        for (let i = 0; i < this.keyPoints.length; i++) {
          this.keyPoints[i].geometry.dispose()
          this.keyPoints[i].material.dispose()
          this.scene.remove(this.keyPoints[i])
        }
      }
      if (this.highlight_points) {
        this.scene.remove(this.highlight_points)
      }
      if (this.selectPointObject) {
        this.scene.remove(this.selectPointObject)
      }
      if (this.dopplerLines) {
        this.scene.remove(this.dopplerLines)
      }
      this.resTracker.dispose()

      if (this.pointsCloudData) {
        if (this.pointsCloudData.children.length > 1) {
          this.dopplerLines = this.pointsCloudData.children[0]
          this.scene.add(this.dopplerLines)
        }
        this.points = this.pointsCloudData.children[this.pointsCloudData.children.length - 1]
        this.scene.add(this.points)
      }

      this.cubeList = new Array()
      this.cubeInstances = new Array()
      this.lineList = new Array()
      this.splitPoints = new Array()
      this.splitObjects = new Map()
    },
    addSplitInstance(annotationObject, playModel) {
      let pointsIndex = annotationObject.threeD.bndbox.x.split(',')
      let fillStyle = this.selectDictLabel(this.colorNames, annotationObject.name)
      if (!fillStyle) {
        fillStyle = 'rgb(255,255,0)'
      }
      fillStyle = fillStyle.replace('rgb(', '').replace(')', '').replace(' ', '')
      fillStyle = fillStyle.split(',')
      let splitViewMode = this.selectDictLabel(this.attributeNames, 'splitViewMode')
      if (splitViewMode && splitViewMode == 'highLight') {
        const position = []
        const colors = []
        const positionArray = this.points.geometry.attributes.position.array
        pointsIndex.forEach((index) => {
          position.push(positionArray[3 * index], positionArray[3 * index + 1], positionArray[3 * index + 2])
          colors.push(parseInt(fillStyle[0]) / 255.0, parseInt(fillStyle[1]) / 255.0, parseInt(fillStyle[2]) / 255.0)
        })
        const geometry = this.track(new THREE.BufferGeometry())
        if (position.length > 0) geometry.setAttribute('position', new THREE.Float32BufferAttribute(position, 3))
        if (colors.length > 0) geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3))
        geometry.computeBoundingSphere()
        let pointSize = parseFloat(Cookies.get('pointSize'))
        if (!pointSize) pointSize = 2
        let material = this.track(new THREE.PointsMaterial({ size: pointSize * 2 }))
        material.color.setHex(0xffffff)
        material.sizeAttenuation = false
        material.vertexColors = true
        material.depthTest = false
        material.fog = false
        const pointsMesh = this.track(new THREE.Points(geometry, material))
        this.scene.add(pointsMesh)
        pointsMesh.mMarkAnnotationId = annotationObject.mMarkAnnotationId
        this.splitPoints.push(pointsMesh)
      }
      // else {
      pointsIndex.forEach((index) => {
        let intensity = 1 //this.points.geometry.attributes.intensities.array[index];
        this.points.geometry.attributes.color.array[3 * index] = (intensity * parseInt(fillStyle[0])) / 255.0
        this.points.geometry.attributes.color.array[3 * index + 1] = (intensity * parseInt(fillStyle[1])) / 255.0
        this.points.geometry.attributes.color.array[3 * index + 2] = (intensity * parseInt(fillStyle[2])) / 255.0
      })

      if (!annotationObject.label) {
        let labelContent = ''
        let _values = undefined
        try {
          let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'labelName'))
          _values = jsonObject.values[annotationObject.name]
        } catch (e) {
          console.log(e)
        }
        labelContent += _values === undefined ? annotationObject.name : _values
        let attrs = annotationObject.threeD.other_attributes
        for (let i = 1; i <= 9; i++) {
          if (attrs['a' + i]) {
            try {
              let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'a' + i + '_3d'))
              _values = jsonObject.values[attrs['a' + i]]
              if (_values) {
                labelContent += '-' + _values
              } else {
                labelContent += '-' + attrs['a' + i]
              }
            } catch (e) {
              labelContent += '-??' + attrs['a' + i].substring(0, 3)
            }
          }
        }
        const text = document.createElement('div')
        text.className = 'label'
        text.style.color = 'rgb(255,255,0)'
        text.textContent = labelContent
        const label = new CSS2DObject(text)
        label.position.x = this.points.geometry.attributes.position.array[3 * pointsIndex[0]]
        label.position.y = this.points.geometry.attributes.position.array[3 * pointsIndex[0] + 1]
        label.position.z = this.points.geometry.attributes.position.array[3 * pointsIndex[0] + 2]
        label.tag = 'des_label'
        label.visible = this.showLabel
        this.scene.add(label)
        this.lineList.push(label)
        annotationObject.label = label
      } else {
        annotationObject.label.visible = true
      }
      this.points.geometry.attributes.color.needsUpdate = true
      this.splitObjects.set(annotationObject.mMarkAnnotationId, annotationObject)
      // }
    },
    hideSplitInstance(annotationObject, playModel) {
      let pointsIndex = annotationObject.threeD.bndbox.x.split(',')
      pointsIndex.forEach((index) => {
        let intensity = this.points.geometry.attributes.intensities.array[index]
        this.points.geometry.attributes.color.array[3 * index] =
          this.points.geometry.attributes.originalColor.array[3 * index]
        this.points.geometry.attributes.color.array[3 * index + 1] =
          this.points.geometry.attributes.originalColor.array[3 * index + 1]
        this.points.geometry.attributes.color.array[3 * index + 2] =
          this.points.geometry.attributes.originalColor.array[3 * index + 2]
        // this.points.geometry.attributes.originalColor.array[3 * index] = intensity * parseInt(fillStyle[0]) / 255.0;
        // this.points.geometry.attributes.originalColor.array[3 * index + 1] = intensity * parseInt(fillStyle[1]) / 255.0;
        // this.points.geometry.attributes.originalColor.array[3 * index + 2] = intensity * parseInt(fillStyle[2]) / 255.0;
      })
      if (annotationObject.label) annotationObject.label.visible = false

      this.points.geometry.attributes.color.needsUpdate = true
    },
    // 添加矩形框数据
    addCube(playModel = false) {
      this.elements_3D = []
      this.remarkLabelList = new Array()

      let _pcdLable = this.selectDictLabel(this.attributeNames, 'renderType') == 'label'
      let _range = this.selectDictLabel(this.attributeNames, 'range')
      if (_range) {
        let xRange = 0
        let yRange = 0
        if (_range.indexOf(';') != -1) {
          let ranges = _range.split(';')
          for (let rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
            _range = ranges[rangeIndex]
            if (_range.indexOf(',') != -1) {
              xRange = parseFloat(_range.split(',')[0])
              yRange = parseFloat(_range.split(',')[1])
            } else {
              xRange = parseFloat(_range)
              yRange = parseFloat(_range)
            }
            this.drawRange(xRange, yRange)
          }
        } else {
          if (_range.indexOf(',') != -1) {
            xRange = parseFloat(_range.split(',')[0])
            yRange = parseFloat(_range.split(',')[1])
          } else {
            xRange = parseFloat(_range)
            yRange = parseFloat(_range)
          }
          this.drawRange(xRange, yRange)
        }
      }

      if (this.annotation && this.annotation.object) {
        for (let i = 0; i < this.annotation.object.length; i++) {
          let description = ''
          let labelContent = ''
          if (!playModel) {
            // if(undefined === this.markAnnotationList[this.annotation.object[i].threeD.other_attributes.a1]) {
            // let _values = this.annotation.object[i].name;
            // try{
            //   let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, "labelName"));
            //   _values = jsonObject.values[_values] ? jsonObject.values[_values] : _values;
            //   jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, "a2_3d"));
            //   if(jsonObject.values[this.annotation.object[i].threeD.other_attributes.a2])
            //     _values += "-" + jsonObject.values[this.annotation.object[i].threeD.other_attributes.a2]
            // }catch (e){
            // }
            // let _data = {
            //   key: this.annotation.object[i].threeD.other_attributes.a1,
            //   value: _values,
            //   // x: this.annotation.object[i].threeD.bndbox.x
            // }
            // this.markAnnotationList.push(_data);
            // }
            description = this.annotation.object[i].name + ':3;'
            let _values = undefined
            try {
              let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'labelName'))
              _values = jsonObject.values[this.annotation.object[i].name]
            } catch (e) {
              console.log(e)
            }
            labelContent += _values === undefined ? this.annotation.object[i].name : _values
            let attrs = this.annotation.object[i].threeD.other_attributes
            for (let i = 1; i <= 9; i++) {
              if (attrs['a' + i]) {
                description += attrs['a' + i] + ';'
                try {
                  let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'a' + i + '_3d'))
                  _values = jsonObject.values[attrs['a' + i]]
                  if (_values === undefined) continue
                  labelContent += '-' + _values
                } catch (e) {}
              }
            }
          }

          let current = this.annotation.object[i].threeD.bndbox
          if (current.z === 'split') {
            this.addSplitInstance(this.annotation.object[i], playModel)
            continue
          }
          let x = current.x.split(';')
          let y = current.y.split(';')
          let z = current.z.split(';')
          let vertices = [],
            eightPoints = [],
            vertices_2d = []
          for (let p = 0; p < 8; p++) {
            vertices.push(new THREE.Vector3(parseFloat(x[p]), parseFloat(y[p]), parseFloat(z[p])))
            vertices_2d.push(new THREE.Vector2(x[p], y[p]))
            eightPoints.push(parseFloat(x[p]))
            eightPoints.push(parseFloat(y[p]))
            eightPoints.push(parseFloat(z[p]))
          }
          let data = {
            trackId: String(this.annotation.object[i].threeD.other_attributes.a1),
            eight_points: eightPoints,
          }
          this.elements_3D.push(data)
          /*
                5_______6
               /|      /|
              4_|_____7 |
              | |     | |
              | 1_____|_2
              |/      |/
              0_______3
            */
          let faces = [
            this.track(new THREE.Face3(4, 3, 7)),
            this.track(new THREE.Face3(4, 0, 3)),

            this.track(new THREE.Face3(7, 2, 6)),
            this.track(new THREE.Face3(7, 3, 2)),

            this.track(new THREE.Face3(4, 7, 6)),
            this.track(new THREE.Face3(4, 6, 5)),

            this.track(new THREE.Face3(1, 6, 2)),
            this.track(new THREE.Face3(1, 5, 6)),

            this.track(new THREE.Face3(0, 4, 5)),
            this.track(new THREE.Face3(0, 5, 1)),

            this.track(new THREE.Face3(0, 1, 2)),
            this.track(new THREE.Face3(0, 2, 3)),
          ]

          let geom = this.track(new THREE.BoxGeometry())
          geom.vertices = vertices
          geom.faces = faces
          geom.computeFaceNormals()
          let fillStyle = this.selectDictLabel(this.colorNames, this.annotation.object[i].name)
          if (!fillStyle) {
            fillStyle = 'rgb(255,255,255)'
          }

          // region 方向箭头
          let orientTheta = this.annotation.object[i].threeD.orient_theta
          let vec1 = [1.0, 0.0]
          let vec2 = [Math.cos(orientTheta), Math.sin(orientTheta)]
          let cos_res = this.calCos(vec1, vec2)
          let angle = Math.acos(cos_res)
          if (vec2[1] <= 0) {
            angle = -angle
          }
          let centerX =
            (parseFloat(x[0]) +
              parseFloat(x[1]) +
              parseFloat(x[2]) +
              parseFloat(x[3]) +
              parseFloat(x[4]) +
              parseFloat(x[5]) +
              parseFloat(x[6]) +
              parseFloat(x[7])) /
            8.0
          let centerY =
            (parseFloat(y[0]) +
              parseFloat(y[1]) +
              parseFloat(y[2]) +
              parseFloat(y[3]) +
              parseFloat(y[4]) +
              parseFloat(y[5]) +
              parseFloat(y[6]) +
              parseFloat(y[7])) /
            8.0
          let centerZ =
            (parseFloat(z[0]) +
              parseFloat(z[1]) +
              parseFloat(z[2]) +
              parseFloat(z[3]) +
              parseFloat(z[4]) +
              parseFloat(z[5]) +
              parseFloat(z[6]) +
              parseFloat(z[7])) /
            8.0
          let pos1 = new THREE.Vector3(centerX, centerY, centerZ)
          let len1Raw = [
            parseFloat(x[1]) - parseFloat(x[0]),
            parseFloat(y[0]) - parseFloat(y[1]),
            parseFloat(z[0]) - parseFloat(z[1]),
          ]
          let len1 = Math.sqrt(len1Raw[0] * len1Raw[0] + len1Raw[1] * len1Raw[1] + len1Raw[2] * len1Raw[2])
          let len2Raw = [
            parseFloat(x[2]) - parseFloat(x[1]),
            parseFloat(y[1]) - parseFloat(y[2]),
            parseFloat(z[1]) - parseFloat(z[2]),
          ]
          let len2 = Math.sqrt(len2Raw[0] * len2Raw[0] + len2Raw[1] * len2Raw[1] + len2Raw[2] * len2Raw[2])
          let orientLen = len1 > len2 ? len1 : len2
          let circleLen = len1 < len2 ? len1 : len2
          let orient = [orientLen * Math.cos(parseFloat(angle)), orientLen * Math.sin(parseFloat(angle)), 0.0]
          let orient3 = [
            20 * Math.cos(parseFloat(angle + Math.PI / 2)),
            20 * Math.sin(parseFloat(angle + Math.PI / 2)),
            0.0,
          ]
          let orient4 = [20 * Math.cos(parseFloat(angle)), 20 * Math.sin(parseFloat(angle)), 0.0]
          let pos2 = new THREE.Vector3(centerX + orient[0], centerY + orient[1], centerZ + orient[2])
          let pos3 = new THREE.Vector3(centerX + orient3[0], centerY + orient3[1], centerZ + orient3[2])
          let pos4 = new THREE.Vector3(centerX + orient4[0], centerY + orient4[1], centerZ + orient4[2])
          let pos5 = new THREE.Vector3(centerX, centerY, centerZ + parseFloat(z[4]) - parseFloat(z[0]))
          let lineGeometry = this.track(new THREE.Geometry())
          let lineMaterial = this.track(
            new THREE.LineBasicMaterial({
              color: fillStyle,
            })
          )
          lineGeometry.vertices.push(pos1, pos2)
          let directLine = this.track(new THREE.Line(lineGeometry, lineMaterial))
          this.lineList.push(directLine)
          this.scene.add(directLine)

          // 四棱锥
          let geometry = this.track(new THREE.ConeBufferGeometry(circleLen / 12, circleLen / 3, 8))
          // try{
          // if (orientLen<1){
          //     geometry = new THREE.ConeBufferGeometry( 0.1, 0.2, 8);
          // }
          // }catch{}

          let material = this.track(new THREE.MeshBasicMaterial({ color: fillStyle }))
          let cone = new THREE.Mesh(geometry, material)
          cone.position.set(centerX + orient[0], centerY + orient[1], centerZ + orient[2])
          // try{
          //   if (orientLen<1){
          //     cone.position.set(centerX + 2*orient[0], centerY + 2*orient[1], centerZ + 2*orient[2]);
          //   }
          // }catch{}

          let angleConver = ((((angle + (Math.PI / 2) * 3) / Math.PI) * 180) % 360).toFixed(3)
          cone.rotateZ(angle + (Math.PI / 2) * 3)
          this.scene.add(cone)
          this.lineList.push(cone)
          // endregion

          let cubeMat1 = this.track(new THREE.MeshBasicMaterial({ color: fillStyle, transparent: true, opacity: 0.2 }))
          let cubeMesh = new THREE.Mesh(geom, cubeMat1)
          if (!playModel) cubeMesh.tag = description
          cubeMesh.mMarkAnnotationId = this.annotation.object[i].mMarkAnnotationId
          cubeMesh.mPoint = {
            x: pos1.x,
            y: pos1.y,
            z: pos1.z,
          }

          let length = 0
          let width = 0
          let height = 0
          if (!playModel) {
            let length_tmp = Math.sqrt(
              (vertices[1].x - vertices[0].x) * (vertices[1].x - vertices[0].x) +
                (vertices[1].y - vertices[0].y) * (vertices[1].y - vertices[0].y)
            ).toFixed(2)
            let width_tmp = Math.sqrt(
              (vertices[3].x - vertices[0].x) * (vertices[3].x - vertices[0].x) +
                (vertices[3].y - vertices[0].y) * (vertices[3].y - vertices[0].y)
            ).toFixed(2)
            length = Math.max(length_tmp, width_tmp)
            width = Math.min(length_tmp, width_tmp)
            height = Math.abs(vertices[0].z - vertices[4].z) //bb.getSize().z.toFixed(2);
            cubeMesh.tag += '长：' + length + ', ' + '宽：' + width + ', ' + '高：' + height
            this.annotationMap.set(data.trackId, { length: length, width: width, height: height })
          }
          let keyPointInfo = null
          // 立方体几何体box作为EdgesGeometry参数创建一个新的几何体
          let edges = this.track(new THREE.EdgesGeometry(geom))
          // 立方体线框，不显示中间的斜线
          let edgesMaterial = this.track(new THREE.LineBasicMaterial({ color: fillStyle, opacity: 0.5 }))
          let line = this.track(new THREE.LineSegments(edges, edgesMaterial))
          // 网格模型和网格模型对应的轮廓线框插入到场景中
          this.scene.add(cubeMesh, line)
          cubeMesh.position.set(line.position.x, line.position.y, line.position.z)
          this.scene.add(cubeMesh)

          const text = document.createElement('div')
          text.className = 'label'
          text.style.color = 'rgb(255,255,255)'
          text.textContent = labelContent
          const label = new CSS2DObject(text)
          label.position.x = centerX
          label.position.y = centerY
          label.position.z = centerZ
          label.tag = 'des_label'
          label.visible = this.showLabel
          this.scene.add(label)
          this.lineList.push(label)

          cubeMesh.arrow = cone
          cubeMesh.directLine = directLine
          cubeMesh.line = line
          cubeMesh.label = label
          cubeMesh.hide = () => {
            cubeMesh.arrow.visible = false
            cubeMesh.directLine.visible = false
            cubeMesh.line.visible = false
            cubeMesh.label.visible = false
            cubeMesh.visible = false
          }
          cubeMesh.show = () => {
            cubeMesh.arrow.visible = true
            cubeMesh.directLine.visible = true
            cubeMesh.line.visible = true
            cubeMesh.label.visible = true
            cubeMesh.visible = true
          }

          this.cubeList.push(cubeMesh)
          this.cubeInstances.push(cubeMesh)
          this.cubeList.push(line)

          // 添加验收标识
          let params = {
            backgroundColor: { r: 255, g: 0, b: 0, a: 1 },
            fontsize: 48,
          }
          // let remarkLabel = this.makeTextSprite(' 验 ', params);
          // remarkLabel.position.set(pos1.x, pos1.y, pos1.z);
          // remarkLabel.missId = data.trackId + '-3d';
          // cubeMesh.remarkLabel = remarkLabel;
          // if(this.elementsRemark[data.trackId + '-3d']) {
          //   this.scene.add(remarkLabel);
          // }
          // this.remarkLabelList.push(remarkLabel);

          if (!playModel) {
            // 存储立方体信息
            let cubeObj = {
              length: length,
              width: width,
              height: height,
              angle: angle,
              angleConver: angleConver,
              edgesMaterial: edgesMaterial,
              keyPointInfo: keyPointInfo
                ? {
                    geom: keyPointInfo[0],
                    mate: keyPointInfo[1],
                    count: keyPointInfo[2],
                  }
                : null,
              keyPointsParams: {
                x,
                y,
                z,
                vertices_2d,
                playModel,
                _pcdLable,
              },
              eightPoints: eightPoints,
              posPoints: {
                pos1: pos1,
                pos2: pos4,
                pos3: pos3,
                pos4: pos5,
              },
              faces: faces,
              vertices: vertices,
              orientTheta: orientTheta,
            }
            this.cubeMap.set(data.trackId, cubeObj)
          }
        }
      }
      for (let prop in this.elementsRemark) {
        if (prop.startsWith('ball') && this.elementsRemark[prop].mType === '3d') {
          let x = this.elementsRemark[prop].x
          let y = this.elementsRemark[prop].y
          let z = this.elementsRemark[prop].z

          let textIcon
          // if(this.elementsRemark[prop].errorType === "miss_mark") {
          //   textIcon = ' 漏 ';
          // }
          // else {
          textIcon = ' 验 '
          // }
          const text = document.createElement('div')
          text.className = 'label'
          text.style.color = 'rgb(255,0,0)'
          text.style['background-color'] = 'rgb(255,255,255)'
          text.textContent = textIcon
          const remarkLabel = new CSS2DObject(text)
          remarkLabel.position.x = x
          remarkLabel.position.y = y
          remarkLabel.position.z = z
          remarkLabel.tag = 'des_label'
          remarkLabel.visible = this.showLabel
          this.scene.add(remarkLabel)
          this.lineList.push(remarkLabel)

          // let remarkLabel = this.makeTextSprite(textIcon, params);
          // remarkLabel.markRemarkId = this.elementsRemark[prop].remarkId;
          // remarkLabel.position.set(x, y, z);
          // this.scene.add(remarkLabel);
          // this.remarkLabelList.push(remarkLabel);
          // remarkLabel.missId = prop;
        }
      }
    },
    drawRange(xRange, yRange) {
      let lineGeometry = this.track(new THREE.Geometry())
      let lineMaterial = this.track(new THREE.LineBasicMaterial({ color: 'rgb(255,255,255)' }))
      let pos1 = new THREE.Vector3(xRange, yRange, 0)
      let pos2 = new THREE.Vector3(xRange, 0 - yRange, 0)
      let pos3 = new THREE.Vector3(0 - xRange, 0 - yRange, 0)
      let pos4 = new THREE.Vector3(0 - xRange, yRange, 0)
      lineGeometry.vertices.push(pos1, pos2)
      let directLine = new THREE.Line(lineGeometry, lineMaterial)
      this.lineList.push(directLine)
      this.scene.add(directLine)
      lineGeometry.vertices.push(pos2, pos3)
      directLine = new THREE.Line(lineGeometry, lineMaterial)
      this.lineList.push(directLine)
      this.scene.add(directLine)
      lineGeometry.vertices.push(pos3, pos4)
      directLine = new THREE.Line(lineGeometry, lineMaterial)
      this.lineList.push(directLine)
      this.scene.add(directLine)
      lineGeometry.vertices.push(pos1, pos4)
      directLine = new THREE.Line(lineGeometry, lineMaterial)
      this.lineList.push(directLine)
      this.scene.add(directLine)
    },
    calCos(a, b) {
      // 点积
      let dotProduct = a[0] * b[0] + a[1] * b[1]
      let d = Math.sqrt(a[0] * a[0] + a[1] * a[1]) * Math.sqrt(b[0] * b[0] + b[1] * b[1])
      return dotProduct / d
    },
    // 矩形框内部的点渲染
    keypointsRender(x, y, z, vertices_2d, playModel = false, _pcdLable = null) {
      function GetCross(p1, p2, p) {
        return (p2.x - p1.x) * (p.y - p1.y) - (p.x - p1.x) * (p2.y - p1.y)
      }
      function IsPointInMatrix(p1, p2, p3, p4, p) {
        let isPointIn = GetCross(p1, p2, p) * GetCross(p3, p4, p) >= 0 && GetCross(p2, p3, p) * GetCross(p4, p1, p) >= 0
        return isPointIn
      }
      if (!playModel) {
        let geometry_temp = this.track(new THREE.BufferGeometry())
        let positions_temp = []
        let colors_temp = []
        let count = 0
        let max_x = Math.max(x[0], x[1], x[2], x[3])
        let max_y = Math.max(y[0], y[1], y[2], y[3])
        let min_x = Math.min(x[0], x[1], x[2], x[3])
        let min_y = Math.min(y[0], y[1], y[2], y[3])
        let min_z = Math.min(z[0], z[4])
        let max_z = Math.max(z[0], z[4])
        for (let i = 0; i < this.points.geometry.attributes.position.array.length / 3; i++) {
          if (
            this.points.geometry.attributes.position.array[3 * i] > max_x ||
            this.points.geometry.attributes.position.array[3 * i] < min_x
          )
            continue
          if (
            this.points.geometry.attributes.position.array[3 * i + 1] > max_y ||
            this.points.geometry.attributes.position.array[3 * i + 1] < min_y
          )
            continue
          if (
            this.points.geometry.attributes.position.array[3 * i + 2] > max_z ||
            this.points.geometry.attributes.position.array[3 * i + 2] < min_z
          )
            continue
          let pointA_2d = new THREE.Vector2(
            this.points.geometry.attributes.position.array[3 * i],
            this.points.geometry.attributes.position.array[3 * i + 1]
          )
          if (IsPointInMatrix(vertices_2d[0], vertices_2d[1], vertices_2d[2], vertices_2d[3], pointA_2d)) {
            if (_pcdLable) {
              colors_temp.push(
                this.points.geometry.attributes.color.array[3 * i],
                this.points.geometry.attributes.color.array[3 * i + 1],
                this.points.geometry.attributes.color.array[3 * i + 2]
              )
            } else {
              this.points.geometry.attributes.color.array[3 * i] = 1.0
              this.points.geometry.attributes.color.array[3 * i + 1] = 0.0
              this.points.geometry.attributes.color.array[3 * i + 2] = 0.0
              colors_temp.push(1, 1, 1)
            }
            positions_temp.push(
              parseFloat(this.points.geometry.attributes.position.array[3 * i]),
              parseFloat(this.points.geometry.attributes.position.array[3 * i + 1]),
              parseFloat(this.points.geometry.attributes.position.array[3 * i + 2])
            )
            count++
          }
        }
        geometry_temp.setAttribute('position', new THREE.Float32BufferAttribute(positions_temp, 3))
        geometry_temp.setAttribute('color', new THREE.Float32BufferAttribute(colors_temp, 3))
        geometry_temp.computeBoundingSphere()
        let canvas_temp = document.createElement('canvas')
        canvas_temp.width = 100
        canvas_temp.height = 100
        let context = canvas_temp.getContext('2d')
        context.fillStyle = 'rgb(255,255,255)'
        context.arc(50, 50, 45, 0, 2 * Math.PI)
        context.fill()
        let texture = this.track(new THREE.Texture(canvas_temp))
        texture.needsUpdate = true
        let material_temp = this.track(
          new THREE.PointsMaterial({
            size: 3,
            vertexColors: THREE.VertexColors,
            depthTest: false,
            fog: false,
            map: texture,
          })
        )

        material_temp.sizeAttenuation = false
        return [geometry_temp, material_temp, count]
      }
      return null
    },
    // 添加文本渲染
    makeTextSprite(message, parameters) {
      if (parameters === undefined) parameters = {}
      var fontface = parameters.hasOwnProperty('fontface') ? parameters['fontface'] : 'Arial'
      var fontsize = parameters.hasOwnProperty('fontsize') ? parameters['fontsize'] : this.pointTextFontSize
      var borderThickness = parameters.hasOwnProperty('borderThickness') ? parameters['borderThickness'] : 1
      var borderColor = parameters.hasOwnProperty('borderColor')
        ? parameters['borderColor']
        : { r: 0, g: 0, b: 0, a: 1.0 }
      var backgroundColor = parameters.hasOwnProperty('backgroundColor')
        ? parameters['backgroundColor']
        : { r: 255, g: 255, b: 255, a: 0.95 }
      var canvas = document.createElement('canvas')
      var context = canvas.getContext('2d')
      context.font = 'Bold ' + fontsize + 'px ' + fontface
      var metrics = context.measureText(message)
      var textWidth = metrics.width
      context.fillStyle =
        'rgba(' + backgroundColor.r + ',' + backgroundColor.g + ',' + backgroundColor.b + ',' + backgroundColor.a + ')'
      context.strokeStyle =
        'rgba(' + borderColor.r + ',' + borderColor.g + ',' + borderColor.b + ',' + borderColor.a + ')'
      context.lineWidth = borderThickness
      this.roundRect(
        context,
        borderThickness / 2,
        borderThickness / 2,
        textWidth + borderThickness,
        fontsize * 1.4 + borderThickness,
        textWidth / 2
      )
      context.fillStyle = 'white'
      context.fillText(message, borderThickness, fontsize + borderThickness)
      var texture = this.track(new THREE.Texture(canvas))
      texture.needsUpdate = true
      var spriteMaterial = this.track(
        new THREE.SpriteMaterial({
          map: texture,
          depthWrite: false,
          transparent: true,
          clipShadows: true,
          depthTest: false,
        })
      )
      // spriteMaterial.sizeAttenuation = false;
      var spritey = this.track(new THREE.Sprite(spriteMaterial))
      spritey.scale.set(4, 2, 1.0)
      return spritey
    },
    // 绘制圆圈图形
    roundRect(ctx, x, y, w, h, r) {
      ctx.beginPath()
      ctx.moveTo(x + r, y)
      ctx.lineTo(x + w - r, y)
      ctx.quadraticCurveTo(x + w, y, x + w, y + r)
      ctx.lineTo(x + w, y + h - r)
      ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h)
      ctx.lineTo(x + r, y + h)
      ctx.quadraticCurveTo(x, y + h, x, y + h - r)
      ctx.lineTo(x, y + r)
      ctx.quadraticCurveTo(x, y, x + r, y)
      ctx.closePath()
      ctx.fill()
      ctx.stroke()
    },
    // 高亮选中的点
    showSelectedPoint(x, y, z) {
      let canvas_temp0 = document.createElement('canvas')
      canvas_temp0.width = 100
      canvas_temp0.height = 100
      let context0 = canvas_temp0.getContext('2d')
      context0.fillStyle = '#ffffff'
      context0.arc(50, 50, 45, 0, 2 * Math.PI)
      context0.fill()
      let texture0 = this.track(new THREE.Texture(canvas_temp0))
      texture0.needsUpdate = true
      let geometry = this.track(new THREE.Geometry())
      let p1 = new THREE.Vector3(x, y, z)
      geometry.vertices.push(p1)
      let material = this.track(
        new THREE.PointsMaterial({
          color: 0xffffff,
          size: 10,
          depthTest: false,
          map: texture0,
        })
      )
      material.sizeAttenuation = false
      material.fog = false
      this.selectPointObject = new THREE.Points(geometry, material)
      this.scene.add(this.selectPointObject)
    },
    render() {
      this.renderEnabled = undefined
      if (this.resizeRendererToDisplaySize(this.renderer)) {
        const canvas = this.renderer.domElement
        this.camera.aspect = canvas.clientWidth / canvas.clientHeight
        this.camera.updateProjectionMatrix()
      }
      this.controls.update()
      this.renderer.render(this.scene, this.camera)
      this.labelRenderer.render(this.scene, this.camera)
    },
    requestRenderIfNotRequested() {
      if (!this.renderEnabled) {
        this.renderEnabled = true
        requestAnimationFrame(this.render)
      }
    },
    resizeRendererToDisplaySize(renderer) {
      const canvas = renderer.domElement
      const width = canvas.clientWidth
      const height = canvas.clientHeight
      const needResize = canvas.width !== width || canvas.height !== height
      if (needResize) {
        renderer.setSize(width, height, false)
      }
      return needResize
    },
    // 重新渲染3D视窗内的批注图标
    reRender() {
      for (let i = 0; i < this.remarkLabelList.length; i++) {
        if (this.elementsRemark[this.remarkLabelList[i].missId]) {
          this.scene.add(this.remarkLabelList[i])
        } else {
          this.scene.remove(this.remarkLabelList[i])
        }
      }
      this.renderer.render(this.scene, this.camera)
      this.labelRenderer.render(this.scene, this.camera)
    },
    onWindowResize() {
      if (this.camera) {
        this.camera.aspect = this.container.offsetWidth / this.container.offsetHeight
        this.renderer.setSize(this.container.offsetWidth, this.container.offsetHeight)
        this.labelRenderer.setSize(this.container.offsetWidth, this.container.offsetHeight)
        this.camera.updateProjectionMatrix()
        this.renderer.render(this.scene, this.camera)
        this.labelRenderer.render(this.scene, this.camera)
      }
    },
    // 鼠标按下事件处理
    onMouseDown(event) {
      this.mouseDown = true
      event.preventDefault()
      this.selectedObject = {
        mMarkAnnotationId: null,
        name: '',
        a1: '',
        a2: '',
        a3: '',
        a4: '',
        a5: '',
        a6: '',
        a7: '',
        a8: '',
        remark: '',
        attributes: [],
        type: '3d',
        imageIndex: '',
        errorType: '',
        mPoint: {
          x: -1,
          y: -1,
          z: -1,
        },
        elementInstance: null,
      }

      this.sync_clear_highlight_objects(this.selectedObject)

      this.scene.remove(this.selectPointObject)
      let rect = this.renderer.domElement.getBoundingClientRect()
      this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1
      this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1
      this.raycaster.setFromCamera(this.mouse, this.camera)
      let intersects = this.raycaster.intersectObjects(this.cubeInstances, true)
      if (intersects.length > 0) {
        if (intersects[0].object.type == 'Mesh') {
          if (this.INTERSECTED) {
            this.transformControls.detach()
            if (this.selectionBox.labelTool === 'cube') {
              this.transformControls.attach(intersects[0].object)
            }
            let _array = intersects[0].object.tag.split(';')
            this.selectedObject.mMarkAnnotationId = intersects[0].object.mMarkAnnotationId
            this.selectedObject.name = _array[0].split(':')[0]
            this.selectedObject.a1 = _array[1]
            this.selectedObject.a2 = _array[2]
            this.selectedObject.a3 = _array[3]
            this.selectedObject.a4 = _array[4]
            this.selectedObject.a5 = _array[5]
            this.selectedObject.a6 = _array[6]
            this.selectedObject.a7 = _array[7]
            this.selectedObject.a8 = _array[8]
            this.selectedObject.remark = this.elementsRemark['ball-' + _array[1] + '-3d']
              ? this.elementsRemark['ball-' + _array[1] + '-3d'].remark
              : ''
            this.selectedObject.errorType = this.elementsRemark['ball-' + _array[1] + '-3d']
              ? this.elementsRemark['ball-' + _array[1] + '-3d'].errorType
              : ''
            this.selectedObject.mPoint = intersects[0].object.mPoint
            this.selectedObject.elementInstance = intersects[0].object.remarkLabel
            this.selectedObject.attributes = []
            let instance = this.cubeMap.get(this.selectedObject.a1)
            if (!instance.keyPointInfo) {
              let tmpInfo = this.keypointsRender(
                instance.keyPointsParams.x,
                instance.keyPointsParams.y,
                instance.keyPointsParams.z,
                instance.keyPointsParams.vertices_2d,
                instance.keyPointsParams.playModel,
                instance.keyPointsParams._pcdLable
              )
              instance.keyPointInfo = {
                geom: tmpInfo[0],
                mate: tmpInfo[1],
                count: tmpInfo[2],
              }
            }

            if (this.pointsFocus) {
              this.scene.remove(this.pointsFocus)
            }
            this.pointsFocus = new THREE.Points(instance.keyPointInfo.geom, instance.keyPointInfo.mate)
            this.scene.add(this.pointsFocus)

            this.cubeMap.set(this.selectedObject.a1, instance)
            this.selectedObject.keyPointsCount = this.cubeMap.get(this.selectedObject.a1).keyPointInfo.count
            for (let i = 1; i <= 9; i++) {
              if (_array[i] && _array[i] != null && _array[i] != '' && _array[i] != 'null') {
                try {
                  let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'a' + i + '_3d'))
                  let _values = jsonObject.values[_array[i]]
                  if (_values == null || _values == undefined || _values == '') _values = _array[i]
                  let key = jsonObject.typeDesc
                  let value = _values
                  let _data = {
                    key,
                    value,
                  }
                  this.selectedObject.attributes.push(_data)
                } catch {}
              }
            }
            this.sync_highlight_objects('3d', this.selectedObject, this.annotationMap.get(this.selectedObject.a1))
          }
        }
      } else if (event.ctrlKey) {
        let intersectPoints = this.raycaster.intersectObjects(this.scene.children, true)
        let intersection = intersectPoints.length > 0 ? intersectPoints[0] : null
        if (intersection !== null && intersection.object.type === 'Points') {
          let x = intersection.point.x
          let y = intersection.point.y
          let z = intersection.point.z

          const textIcon = ' 验 '
          const text = document.createElement('div')
          text.className = 'label'
          text.style.color = 'rgb(255,0,0)'
          text.style['background-color'] = 'rgb(255,255,255)'
          text.textContent = textIcon
          const remarkLabel = new CSS2DObject(text)
          remarkLabel.position.x = x
          remarkLabel.position.y = y
          remarkLabel.position.z = z
          remarkLabel.tag = 'des_label'
          remarkLabel.visible = this.showLabel
          this.scene.add(remarkLabel)
          this.lineList.push(remarkLabel)

          let missId = 'lou-3d-' + remarkLabel.id
          remarkLabel.missId = missId
          this.selectedObject.a1 = missId
          this.selectedObject.errorType = 'miss_mark'
          this.selectedObject.elementInstance = remarkLabel
          this.selectedObject.mPoint = {
            x: intersection.point.x,
            y: intersection.point.y,
            z: intersection.point.z,
          }
          this.showSelectedPoint(intersection.point.x, intersection.point.y, intersection.point.z)
          this.handleElementComments(missId, this.selectedObject)
        }
        // else if (intersection !== null && intersection.object.type === 'Sprite' && intersection.object.missId) {
        //   this.selectedObject.elementInstance = intersection.object;
        //   this.handleElementComments(intersection.object.missId, "", this.selectedObject);
        //   this.scene.remove(intersection.object);
        //   for(let i = 0; i < this.remarkLabelList.length; i++) {
        //     if(this.remarkLabelList[i].missId && this.remarkLabelList[i].missId == intersection.object.missId) {
        //       this.remarkLabelList.splice(i, 1);
        //       break;
        //     }
        //   }
        // }
      } else {
        if (event.buttons != 1) {
          return
        }
        let intersectPoints = this.raycaster.intersectObjects(this.scene.children, true)
        let intersection = intersectPoints.length > 0 ? intersectPoints[0] : null
        if (intersection !== null && intersection.object.type === 'Sprite' && intersection.object.missId) {
          this.showSelectedPoint(
            intersection.object.position.x,
            intersection.object.position.y,
            intersection.object.position.z
          )
        }
      }
    },
    onMouseUp() {
      this.mouseDown = false
    },
    // 鼠标移动事件处理
    onMouseMove(event) {
      if (this.renderer.domElement) {
        event.preventDefault()
        let rect = this.renderer.domElement.getBoundingClientRect()
        this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1
        this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1

        this.raycaster.setFromCamera(this.mouse, this.camera)
        let intersects = this.raycaster.intersectObjects(this.cubeInstances, true)
        if (intersects.length > 0) {
          if (intersects[0].object != this.INTERSECTED) {
            if (intersects[0].object.type == 'Mesh') {
              // this.renderEnabled = true;
              // restore previous intersection object (if it exists) to its original color
              if (this.INTERSECTED) this.INTERSECTED.material.color.setHex(this.INTERSECTED.currentHex)
              // store reference to closest object as current intersection object
              this.INTERSECTED = intersects[0].object
              // store color of closest object (for later restoration)
              this.INTERSECTED.currentHex = this.INTERSECTED.material.color.getHex()
              // set a new color for closest object
              this.INTERSECTED.material.color.setHex(0xffff00)

              const message = intersects[0].object.tag
              // if(this.checkrole(['admin']) || this.checkrole(['checker'])) {
              let worldVector = new THREE.Vector3(
                intersects[0].object.geometry.boundingSphere.center.x,
                intersects[0].object.geometry.boundingSphere.center.y,
                intersects[0].object.geometry.boundingSphere.center.z
              )
              //世界坐标转标准设备坐标
              let stdVector = worldVector.project(this.camera)
              let a = window.innerWidth / 2
              let b = window.innerHeight / 2
              //标准设备坐标转屏幕坐标x,y
              let x = Math.round(stdVector.x * a + a)
              let y = Math.round(-stdVector.y * b + b)
              this.ShowTip(message, x, y)
              // }
            } else {
              this.HideTip()
            }
          }
        } else {
          this.HideTip()
          if (this.INTERSECTED) {
            this.INTERSECTED.material.color.setHex(this.INTERSECTED.currentHex)
            this.INTERSECTED = null
          }
        }

        this.renderer.render(this.scene, this.camera)
        this.labelRenderer.render(this.scene, this.camera)
      }
    },
    onMouseWheel() {
      // this.renderEnabled = true;
    },
    // 点云数据转3D点云对象
    loadJsonPCD(pointsCloud) {
      let positions = []
      let color = []
      for (var i = 0; i < pointsCloud.length; i++) {
        let x = pointsCloud[i][0]
        let y = pointsCloud[i][1]
        let z = pointsCloud[i][2]
        positions.push(x, y, z)
        let tmp = colorRender(z, this.renderType)
        color.push(tmp[0], tmp[1], tmp[2])
      }
      let canvas_temp0 = document.createElement('canvas')
      canvas_temp0.width = 100
      canvas_temp0.height = 100
      let context0 = canvas_temp0.getContext('2d')
      context0.fillStyle = '#ffffff'
      context0.arc(50, 50, 45, 0, 2 * Math.PI)
      context0.fill()
      let texture0 = this.track(new THREE.Texture(canvas_temp0))
      texture0.needsUpdate = true
      let material = this.track(
        new THREE.PointsMaterial({ size: 2, vertexColors: THREE.VertexColors, depthTest: false, map: texture0 })
      )
      material.color.setHex(0xffffff)
      material.sizeAttenuation = false
      material.vertexColors = THREE.VertexColors
      material.depthTest = false
      material.fog = false
      let geometry = this.track(new THREE.BufferGeometry())
      geometry.attributes.color = new THREE.Float32BufferAttribute(color, 3)
      geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3))
      geometry.computeBoundingSphere()
      return new THREE.Points(geometry, material)
    },
    checkrole(role) {
      return checkRole(role)
    },
    showAttributesText2D(show) {
      this.lineList.forEach((element) => {
        if (element.tag === 'des_label') {
          element.visible = show
        }
      })
      this.reRender()
    },
    addSplitCallback(parms) {
      if (parms.ret === 'confirm') {
        let fillStyle = this.selectDictLabel(this.colorNames, parms.form.name)
        if (!fillStyle) {
          fillStyle = 'rgb(255,255,0)'
        }
        fillStyle = fillStyle.replace('rgb(', '').replace(')', '').replace(' ', '')
        fillStyle = fillStyle.split(',')
        this.tmpSplitPoints.forEach((index) => {
          let intensity = this.points.geometry.attributes.intensities.array[index]
          this.points.geometry.attributes.color.array[3 * index] = (intensity * parseInt(fillStyle[0])) / 255.0
          this.points.geometry.attributes.color.array[3 * index + 1] = (intensity * parseInt(fillStyle[1])) / 255.0
          this.points.geometry.attributes.color.array[3 * index + 2] = (intensity * parseInt(fillStyle[2])) / 255.0
        })
        this.tmpMinusSplitPoints.forEach((index) => {
          this.points.geometry.attributes.color.array[3 * index] =
            this.points.geometry.attributes.originalColor.array[3 * index]
          this.points.geometry.attributes.color.array[3 * index + 1] =
            this.points.geometry.attributes.originalColor.array[3 * index + 1]
          this.points.geometry.attributes.color.array[3 * index + 2] =
            this.points.geometry.attributes.originalColor.array[3 * index + 2]
        })
        this.points.geometry.attributes.color.needsUpdate = true
        this.renderer.render(this.scene, this.camera)
        this.tmpSplitPoints = []
        this.tmpMinusSplitPoints = []
      } else {
      }
    },
    focusObject(annotation) {
      if (annotation.z === 'split') {
        if (this.splitRange) {
          if (this.splitRange.pointsMesh) this.scene.remove(this.splitRange.pointsMesh)
          this.scene.remove(this.splitRange)
        }
        let fillStyle = this.selectDictLabel(this.colorNames, annotation.name)
        if (!fillStyle) {
          fillStyle = 'rgb(255, 255, 0)'
        }
        const vertices = []
        const position = []
        const colors = []
        let zRange = 0
        const pointsIndex = annotation.x.split(',')
        const pointsArray = this.points.geometry.attributes.position
          ? this.points.geometry.attributes.position.array
          : []
        pointsIndex.forEach((i) => {
          i = parseInt(i)
          const vertex = new THREE.Vector3(pointsArray[3 * i], pointsArray[3 * i + 1], pointsArray[3 * i + 2])
          vertices.push(vertex)
          zRange += Math.abs(pointsArray[i + 2])
          position.push(pointsArray[3 * i], pointsArray[3 * i + 1], pointsArray[3 * i + 2])
          let color = fillStyle.replace('rgb(', '').replace(')', '').replace(' ', '').split(',')
          colors.push(parseInt(color[0]) / 255.0, parseInt(color[1]) / 255.0, parseInt(color[2]) / 255.0)
        })

        if (vertices.length === 0) return

        if (zRange == 0 || vertices.length < 4) {
          const v = vertices[vertices.length - 1]
          let vertex = new THREE.Vector3(v.x + 0.001, v.y, v.z)
          vertices.push(vertex)
          vertex = new THREE.Vector3(v.x, v.y + 0.001, v.z)
          vertices.push(vertex)
          vertex = new THREE.Vector3(v.x, v.y, v.z + 0.001)
          vertices.push(vertex)
        }

        const meshMaterial = this.track(
          new THREE.MeshBasicMaterial({
            color: fillStyle,
            opacity: 0,
            transparent: true,
          })
        )

        const meshGeometry = this.track(new ConvexGeometry(vertices))
        meshGeometry.computeBoundingSphere()

        this.splitRange = this.track(new THREE.Mesh(meshGeometry, meshMaterial))
        this.splitRange.renderOrder = 1
        this.scene.add(this.splitRange)

        let splitViewMode = this.selectDictLabel(this.attributeNames, 'splitViewMode')
        if (!splitViewMode || splitViewMode !== 'highLight') {
          const geometry = this.track(new THREE.BufferGeometry())
          if (position.length > 0) geometry.setAttribute('position', new THREE.Float32BufferAttribute(position, 3))
          if (colors.length > 0) geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3))
          geometry.computeBoundingSphere()
          let material = this.track(new THREE.PointsMaterial({ size: 4 }))
          material.color.setHex(0xffffff)
          material.sizeAttenuation = false
          material.vertexColors = true
          material.depthTest = false
          material.fog = false
          const pointsMesh = this.track(new THREE.Points(geometry, material))
          this.scene.add(pointsMesh)

          this.splitRange.pointsMesh = pointsMesh
        }

        const x = this.splitRange.geometry.boundingSphere.center.x
        const y = this.splitRange.geometry.boundingSphere.center.x
        const z = this.splitRange.geometry.boundingSphere.center.x

        const distance = 20 * this.splitRange.geometry.boundingSphere.radius
        let selectCenterPoint = this.calcCameraOffsetPosition(this.splitRange.geometry.boundingSphere.center, distance)
        this.controls.target.copy(this.splitRange.geometry.boundingSphere.center)
        this.camera.position.set(selectCenterPoint.x1, selectCenterPoint.y1, selectCenterPoint.z1)
        this.camera.lookAt(x, y, z)
        this.camera.updateMatrix()
        this.renderer.render(this.scene, this.camera)
        this.controls.update()
      }
    },
    changeTransformControlMode(mode) {
      if (this.transformControls) {
        this.transformControls.setMode(mode)
      }
    },
    changeLabelTool(toolName) {
      const { selectionBox } = this
      if (!selectionBox) {
        return
      }

      if (toolName) {
        this.selectionBox.labelTool = toolName
        if (toolName !== 'view') {
          this.splitObjects.forEach((element) => {
            this.addSplitInstance(element, false)
          })
          this.splitPoints.forEach((element) => {
            element.visible = false
          })
        } else {
          this.splitPoints.forEach((element) => {
            element.visible = true
          })
        }
      } else {
        if (this.selectionBox.labelTool === 'view' || this.selectionBox.labelTool === 'minus') {
          this.selectionBox.labelTool = 'point'
        } else {
          this.selectionBox.labelTool = 'minus'
        }
      }
    },
  },
  created() {
    this.selectedObjectA1 = this.$route.query.selectedObjectA1
  },
  mounted() {
    window.addEventListener('resize', this.onWindowResize, false)
  },
  beforeDestroy() {
    cancelAnimationFrame(this.animationFrameId)
    this.camera = null
    if (this.renderer) {
      this.renderer.domElement.removeEventListener('mousemove', this.onMouseMove, false)
      this.renderer.domElement.removeEventListener('mousedown', this.onMouseDown, false)
      this.renderer.domElement.removeEventListener('mouseup', this.onMouseUp, false)
      this.renderer.domElement.removeEventListener('wheel', this.onMouseWheel, false)
      this.renderer.forceContextLoss()
      this.renderer = null
    }
    window.removeEventListener('resize', this.onWindowResize, false)
  },
}
</script>
<style lang="scss" scoped>
/* Scale canvas with resize attribute to full size */
canvas[resize] {
  width: 100%;
  height: auto;
}
.point-cloud-container {
  background: #111;
  canvas {
    width: 100%;
    height: 100%;
  }
}
.plan-view-drawer {
  position: absolute;
  right: 0px;
  top: 0px;
  height: 83vh;
  z-index: 1000;
  left: 80%;
  background: #fff;
}
.plane-view-card /deep/ .el-card__header {
  padding: 0 12px;
  line-height: 28px;
  height: 28px;
  min-height: auto;
}
.label {
  text-shadow: -1px 1px 1px rgb(0, 0, 0);
  margin-left: 25px;
  font-size: 20px;
}
/deep/.selectBox {
  border: 1px solid #ffff00;
  background-color: rgba(255, 248, 189, 0.253);
  position: fixed;
}
</style>
